package cn.chiship.sdk.core.util;

import cn.chiship.sdk.core.exception.custom.SystemErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.IsoFields;
import java.util.*;

/**
 * 时间工具类
 *
 * @author lijian
 */
public class DateUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);

	private static final int MONTH_COUNT = 12;

	public static final String YYYY = "yyyy";

	public static final String YYYY_MM = "yyyy-MM";

	public static final String YYYY_MM_DD = "yyyy-MM-dd";

	public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

	public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

	private DateUtils() {
	}

	/**
	 * 获取当前Date型日期
	 */
	public static Date getNowDate() {
		return new Date();
	}

	/**
	 * 获取当前日期, 默认格式为yyyy-MM-dd
	 */
	public static String getDate() {
		return dateTimeNow(YYYY_MM_DD);
	}

	/**
	 * 获取当前日期时间，默认格式为yyyy-MM-dd HH:mm:ss
	 */
	public static String getTime() {
		return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
	}

	/**
	 * 获取当前日期时间，默认格式为yyyyMMddHHmmss
	 */
	public static String dateTimeNow() {
		return dateTimeNow(YYYYMMDDHHMMSS);
	}

	/**
	 * 时间戳格式化时间，默认格式为yyyyMMddHHmmss
	 */
	public static String dateTime(Long time) {
		return new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS).format(new Date(time));
	}

	/**
	 * 时间戳根据传入格式格式化时间
	 */
	public static String dateTime(Long time, String format) {
		return new SimpleDateFormat(format).format(new Date(time));
	}

	public static final String dateTimeNow(final String format) {
		return parseDateToStr(format, new Date());
	}

	public static final String dateTime(final Date date) {
		return parseDateToStr(YYYY_MM_DD, date);
	}

	public static final String parseDateToStr(final String format, final Date date) {
		return new SimpleDateFormat(format).format(date);
	}

	public static final Date dateTime(final String format, final String ts) {
		try {
			return new SimpleDateFormat(format).parse(ts);
		}
		catch (ParseException e) {
			throw new SystemErrorException(e);
		}
	}

	/**
	 * 获取服务器启动时间
	 */
	public static Date getServerStartDate() {
		long time = ManagementFactory.getRuntimeMXBean().getStartTime();
		return new Date(time);
	}

	/**
	 * 计算两个时间差
	 */
	public static String getDatePoor(Date endDate, Date nowDate) {
		long nd = 1000L * 24L * 60L * 60L;
		long nh = 1000L * 60L * 60L;
		long nm = 1000L * 60L;
		long ns = 1000L;
		// 获得两个时间的毫秒时间差异
		long diff = endDate.getTime() - nowDate.getTime();
		// 计算差多少天
		long day = diff / nd;
		// 计算差多少小时
		long hour = diff % nd / nh;
		// 计算差多少分钟
		long min = diff % nd % nh / nm;
		// 计算差多少秒//输出结果
		long sec = diff % nd % nh % nm / ns;
		return day + "天" + (hour > 9 ? hour : "0" + hour) + "小时" + (min > 9 ? min : "0" + min) + "分钟"
				+ (sec > 9 ? sec : "0" + sec) + "秒";
	}

	/**
	 * 获得指定区间内所有月份
	 * @param beginTime
	 * @param endTime
	 * @param isReverse
	 * @return 结果
	 */
	public static List<String> getMonthsByInterval(String beginTime, String endTime, Boolean isReverse) {
		try {
			Date startDate = new SimpleDateFormat(YYYY_MM).parse(beginTime);
			Date endDate = new SimpleDateFormat(YYYY_MM).parse(endTime);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startDate);
			int startYear = calendar.get(Calendar.YEAR);
			int startMonth = calendar.get(Calendar.MONTH);
			calendar.setTime(endDate);
			int endYear = calendar.get(Calendar.YEAR);
			int endMonth = calendar.get(Calendar.MONTH);
			List<String> months = new ArrayList<>();
			for (int i = startYear; i <= endYear; i++) {
				String date = "";
				if (startYear == endYear) {
					for (int j = startMonth; j <= endMonth; j++) {
						if (j < 9) {
							date = i + "-0" + (j + 1);
						}
						else {
							date = i + "-" + (j + 1);
						}
						months.add(date);
					}

				}
				else {
					if (i == startYear) {
						for (int j = startMonth; j < MONTH_COUNT; j++) {
							if (j < 9) {
								date = i + "-0" + (j + 1);
							}
							else {
								date = i + "-" + (j + 1);
							}
							months.add(date);
						}
					}
					else if (i == endYear) {
						for (int j = 0; j <= endMonth; j++) {
							if (j < 9) {
								date = i + "-0" + (j + 1);
							}
							else {
								date = i + "-" + (j + 1);
							}
							months.add(date);
						}
					}
					else {
						for (int j = 0; j < MONTH_COUNT; j++) {
							if (j < 9) {
								date = i + "-0" + (j + 1);
							}
							else {
								date = i + "-" + (j + 1);
							}
							months.add(date);
						}
					}

				}

			}
			if (Boolean.TRUE.equals(isReverse)) {
				Collections.reverse(months);
			}
			return months;

		}
		catch (Exception e) {
			LOGGER.error("发生异常", e);
		}
		return new ArrayList<>();
	}

	/**
	 * 检测日期格式是否合法
	 * @param format
	 * @param ts
	 * @return Boolean
	 */
	public static final Boolean checkLegal(final String format, final String ts) {
		try {
			new SimpleDateFormat(format).parse(ts);
			return true;
		}
		catch (ParseException e) {
			return false;
		}
	}

	/**
	 * 获取昨天
	 * @return String
	 */
	public static String getYesterday() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -1);
		Date time = cal.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(time);
	}

	/**
	 * 获取昨天开始日期
	 * @return String
	 */
	public static String getYesterdayStart() {
		return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,
				DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getYesterday() + " 00:00:00"));
	}

	/**
	 * 获取昨天结束日期
	 * @return String
	 */
	public static String getYesterdayEnd() {
		return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,
				DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getYesterday() + " 23:59:59"));
	}

	/**
	 * 获取本月开始日期
	 * @return String
	 **/
	public static String getMonthStart() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MONTH, 0);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		Date time = cal.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(time) + " 00:00:00";
	}

	/**
	 * 获取本月最后一天
	 * @return String
	 **/
	public static String getMonthEnd() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		Date time = cal.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(time) + " 23:59:59";
	}

	/**
	 * 获取本周的第一天
	 * @return String
	 **/
	public static String getWeekStart() {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.WEEK_OF_MONTH, 0);
		cal.set(Calendar.DAY_OF_WEEK, 2);
		Date time = cal.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(time) + " 00:00:00";
	}

	/**
	 * 获取本周的最后一天
	 * @return String
	 **/
	public static String getWeekEnd() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.DAY_OF_WEEK, cal.getActualMaximum(Calendar.DAY_OF_WEEK));
		cal.add(Calendar.DAY_OF_WEEK, 1);
		Date time = cal.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(time) + " 23:59:59";
	}

	/**
	 * 获取本周所有时间集合
	 * @return List<Date>
	 */
	public static List<Date> getWeekDates() {
		List<Date> weekDates = new ArrayList<>();
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		for (int i = 0; i < 7; i++) {
			weekDates.add(calendar.getTime());
			calendar.add(Calendar.DATE, 1);
		}
		return weekDates;
	}

	/**
	 * 获取本月所有时间集合
	 * @return List<Date>
	 */
	public static List<Date> getMonthDates() {
		List<Date> monthDates = new ArrayList<>();
		LocalDate start = LocalDate.now().withDayOfMonth(1);
		LocalDate end = start.plusMonths(1).minusDays(1);
		for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) {
			ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault());
			monthDates.add(Date.from(zonedDateTime.toInstant()));
		}
		return monthDates;
	}

	/**
	 * 获取本季度所有时间集合
	 * @return List<Date>
	 */
	public static List<Date> getQuarterDates() {
		List<Date> quarterDates = new ArrayList<>();
		LocalDate today = LocalDate.now();
		int quarter = today.get(IsoFields.QUARTER_OF_YEAR);
		LocalDate firstDayOfQuarter = today.withDayOfYear((quarter - 1) * 92 + 1);
		LocalDate lastDayOfQuarter = today.withDayOfYear(quarter * 92);

		LocalDate current = firstDayOfQuarter;
		while (!current.isAfter(lastDayOfQuarter)) {
			ZonedDateTime zonedDateTime = current.atStartOfDay(ZoneId.systemDefault());
			quarterDates.add(Date.from(zonedDateTime.toInstant()));
			current = current.plusDays(1);
		}
		return quarterDates;
	}

	/**
	 * 获取指定本季度所有月份
	 * @return List<Integer>
	 */

	public static List<Integer> getQuarterMonths() {
		return getQuarterMonths(DateUtils.getNowDate());
	}

	/**
	 * 获取指定日期季度所有月份
	 * @return List<Integer>
	 */

	public static List<Integer> getQuarterMonths(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		List<Integer> months = new ArrayList<>();
		int currentMonth = calendar.get(Calendar.MONTH) + 1;
		int currentQuarter = (currentMonth - 1) / 3 + 1;
		int firstMonthOfQuarter = (currentQuarter - 1) * 3 + 1;

		for (int i = 0; i < 3; i++) {
			months.add(firstMonthOfQuarter + i);
		}

		return months;
	}

	/**
	 * 获取本年的第一天
	 * @return String
	 **/
	public static String getYearStart() {
		return new SimpleDateFormat(YYYY).format(new Date()) + "-01-01 00:00:00";
	}

	/**
	 * 获取本年的最后一天
	 * @return String
	 **/
	public static String getYearEnd() {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.MONTH, calendar.getActualMaximum(Calendar.MONTH));
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		Date currYearLast = calendar.getTime();
		return new SimpleDateFormat(YYYY_MM_DD).format(currYearLast) + " 23:59:59";
	}

	/**
	 * ISO 8601格式时间转时间戳
	 * @param ts
	 * @return
	 */
	public static Long isoDateToTimestamp(String ts) {
		DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
		LocalDateTime dateTime = LocalDateTime.parse(ts, formatter);
		ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.systemDefault());
		return zonedDateTime.toEpochSecond() * 1000;
	}

}
